package grape.common.rest.mvc;

import com.baomidou.mybatisplus.core.metadata.IPage;
import grape.common.exception.CBaseException;
import grape.common.exception.ExceptionTools;
import grape.common.exception.runtime.InvalidParamsException;
import grape.common.exception.runtime.RBaseException;
import grape.common.rest.form.BasePageForm;
import grape.common.rest.form.BaseTreePageForm;
import grape.common.rest.vo.BaseTreeVo;
import grape.common.rest.vo.TreeNodeVo;
import grape.common.service.common.IBaseTreeService;
import grape.common.service.common.dataconstraint.ConstraintCompiledContent;
import grape.common.service.po.TreeBasePo;
import grape.common.service.query.BasePoQuery;
import grape.common.service.update.BaseUpdateWithNullCondition;
import lombok.Data;
import lombok.EqualsAndHashCode;
import org.springframework.beans.factory.annotation.Autowired;

import java.util.*;
import java.util.stream.Collectors;

/**
 * 正常业务实体的controller基类,提供一些通用方法
 * @param <Vo> 简单vo
 * @param <Po> po
 */
@Data
@EqualsAndHashCode(callSuper=false)
public abstract class BaseTreeController<Vo extends BaseTreeVo,Po extends TreeBasePo<Po>> extends BaseController<Vo,Po> {

    @Autowired
    protected IBaseTreeService<Po> service;

    @Autowired
    protected WebMapper<Vo,Po> mapperConverter;

    /**
     * 单表添加
     * @param poQuery
     * @return
     */
    public Vo create(Po poQuery){
        Po dbPo = null;
        String parentId = poQuery.getParentId();
        if (!isStrEmpty(parentId)) {
            dbPo = service.insertChild(poQuery,parentId);
            return returnCreate(dbPo);
        }else {
            return super.create(poQuery);
        }
    }

    /**
     * 单表根据id获取
     * @param id
     * @return
     */

    public boolean deleteById(String id){
        if (service.getChildrenCount(id) > 0) {
            throw ExceptionTools.failRE("删除失败,当前节点下还有子节点");
        }
        return super.deleteById(id);
    }

    /**
     * 单表更新
     * @param poQuery
     * @param isFull 是否全字段更新
     * @return
     */
    public Vo update(Po poQuery,boolean isFull){
        poQuery = beforUpdate(poQuery);
        return super.update(poQuery,isFull);
    }
    /**
     *
     * @param poQuery
     * @return
     */
    public Vo update(BaseUpdateWithNullCondition<Po> poQuery){
        poQuery.setPo(beforUpdate(poQuery.getPo()));
        return super.update(poQuery);
    }

    @Override
    public IPage<Vo> listPage(Po poQuery, BasePageForm pageForm) {
        includeGrandChildrenIfNeccesary(poQuery, pageForm);
        return super.listPage(poQuery, pageForm);
    }

    @Override
    public IPage<Vo> listPage(BasePoQuery<Po> poQuery, BasePageForm pageForm) {
        includeGrandChildrenIfNeccesary(poQuery.getPoQuery(), pageForm);
        return super.listPage(poQuery, pageForm);
    }

    @Override
    public List<Vo> list(Po poQuery) {
        return super.list(poQuery);
    }

    @Override
    public List<Vo> list(BasePoQuery<Po> poQuery) {
        return super.list(poQuery);
    }

    /**
     * 评断是否也查询孙子节点
     * @param poQuery
     * @param pageForm
     */
    private void includeGrandChildrenIfNeccesary(Po poQuery, BasePageForm pageForm){
        if (!isStrEmpty(poQuery.getParentId())
                && pageForm instanceof BaseTreePageForm
                && ((BaseTreePageForm) pageForm).getIsIncludeGrandChildren() !=null
                && ((BaseTreePageForm) pageForm).getIsIncludeGrandChildren()) {

            Po po = service.getById(poQuery.getParentId());
            poQuery.setParentId(null);
            poQuery = service.initQueryChildrenParentIdXByParentLevel(poQuery, po);
        }
    }
    /**
     * 更新以前设置树结束关系
     * @param poQuery
     * @return
     */
    protected Po beforUpdate(Po poQuery){
        // 判断父级是否修改
        Po poDb = service.getById(poQuery.getId());
        //父级不相等，则有修改父级
        if(!isEqual(poDb.getParentId(), poQuery.getParentId())){
            // 判断该节点下是否有子节点，如果有，不允许修改
            int childrenCount = service.getChildrenCount(poQuery.getId());
            if (childrenCount > 0) {
                throw new InvalidParamsException("当前节点下还有子节点，不允许修改父节点");
            }
        }
        if (!isStrEmpty(poQuery.getParentId())) {
            if (isEqual(poQuery.getId(),poQuery.getParentId())) {
                throw new InvalidParamsException("不能将父级设置为自己");
            }
            poQuery = service.initParentIdXByParent(poQuery, poQuery.getParentId());
        }
        return poQuery;
    }

    /**
     * 根据父id请求
     * @param parentId
     * @return
     */
    public List<Vo> getByParentId(String parentId){
        List<Po> r;
        if (parentId == null) {
            r = ((IBaseTreeService) service).getRoot();
        }else {
            r = ((IBaseTreeService) service).getChildren(parentId);
        }
        return super.posToVos(r);
    }
    /**
     * 根据父id请求
     * @param parentId
     * @param query 额外过滤条件
     * @return
     */
    public List<Vo> getByParentId(String parentId,Po query){
        List<Po> r;
        if (parentId == null) {
            r = ((IBaseTreeService) service).getRoot(query);
        }else {
            r = ((IBaseTreeService) service).getChildren(parentId,query);
        }
        return super.posToVos(r);
    }
    /**
     * 检查机构树结构是否完整
     */

    public boolean checkTreeStruct(){
        try {
            service.checkTreeStruct(null);
        } catch (CBaseException e) {
            throw new RBaseException(e.getMessage());
        }
        return true;
    }

    /**
     * 移动节点
     * @param id
     * @param parentId
     * @return
     */
    public boolean moveNode(String id,String parentId){
        int i = service.moveNode(id, parentId);
        return i>0;
    }

    /**
     * 只是简单的对象转换，支持懒加载
     * @param list
     * @return
     */
    public  List<TreeNodeVo<Vo>> listToTreeNodeVo(List<Vo> list){
        List<TreeNodeVo<Vo>> temp = new ArrayList<>(list.size());
        TreeNodeVo tempTreeNodeVo = null;
        for (Vo t : list) {
            tempTreeNodeVo = new TreeNodeVo<>(t,null,false);
            tempTreeNodeVo.setId(t.getId());
            tempTreeNodeVo.setHasChildren(service.hasChildren(t.getId()));
            temp.add(tempTreeNodeVo);
        }
        return temp;
    }
    /**
     * list转为树结构
     * 主要是将打平的树数据转为树结构，不支持懒加载使用
     * @param list
     * @return
     */
    public List<TreeNodeVo<Vo>> listToTree(List<Vo> list){
        List<TreeNodeVo<Vo>> temp = listToTreeNodeVo(list);
        List<TreeNodeVo<Vo>> result = new ArrayList<>();
        TreeNodeVo tempTreeNodeVo = null;
        Iterator<TreeNodeVo<Vo>> iterator = temp.iterator();
        Set<String> hasHandledIds = new HashSet<>();
        while (iterator.hasNext()) {
            TreeNodeVo<Vo> next = iterator.next();
            //  根节点
            if (next.getNode().getParentId() == null) {
                result.add(next);
                iterator.remove();
            }
            for (TreeNodeVo<Vo> treeNodeVo : temp) {
                if(hasHandledIds.contains(treeNodeVo.getNode().getId())){
                    continue;
                }
                if (next.getNode().getId().equals(treeNodeVo.getNode().getParentId())) {
                    if (next.getChildren() == null) {
                        next.setChildren(new ArrayList<>());
                    }
                    next.setHasChildren(true);
                    next.getChildren().add(treeNodeVo);
                    hasHandledIds.add(treeNodeVo.getNode().getId());
                }
            }
        }
        return result;
    }

    /******************************** 以下为数据约束相关 *******************************************************/
    /**
     * 单表根据id删除，重载数据对象约束
     * @param id
     * @return
     */

    public boolean deleteById(String id,List<ConstraintCompiledContent> constraintContent){
        if (service.getChildrenCount(id) > 0) {
            throw ExceptionTools.failRE("删除失败,当前节点下还有子节点");
        }
        return super.deleteById(id,constraintContent);
    }

    @Override
    public Vo update(Po poQuery, List<ConstraintCompiledContent> constraintContent) {
        poQuery = beforUpdate(poQuery);
        return super.update(poQuery, constraintContent);
    }

    @Override
    public Vo update(BaseUpdateWithNullCondition<Po> poQuery, List<ConstraintCompiledContent> constraintContent) {
        poQuery.setPo(beforUpdate(poQuery.getPo()));
        return super.update(poQuery, constraintContent);
    }

    @Override
    public Vo update(Po poQuery, boolean isFull, List<ConstraintCompiledContent> constraintContent) {
        poQuery = beforUpdate(poQuery);
        return super.update(poQuery, isFull, constraintContent);
    }

    @Override
    public IPage<Vo> listPage(Po poQuery, BasePageForm pageForm, List<ConstraintCompiledContent> constraintContent) {
        includeGrandChildrenIfNeccesary(poQuery, pageForm);
        return super.listPage(poQuery, pageForm, constraintContent);
    }

    @Override
    public IPage<Vo> listPage(BasePoQuery<Po> poQuery, BasePageForm pageForm, List<ConstraintCompiledContent> constraintContent) {
        includeGrandChildrenIfNeccesary(poQuery.getPoQuery(), pageForm);
        return super.listPage(poQuery, pageForm, constraintContent);
    }

}
